package com.qianli.cashmama.trade.application.contract;

import com.fenqiguanjia.helpers.DecimalUtils;
import com.fqgj.base.services.amazon.AmazonS3Service;
import com.fqgj.base.services.oss.OSSService;
import com.fqgj.common.api.Response;
import com.fqgj.common.utils.DateUtil;
import com.fqgj.exception.common.ApplicationException;
import com.fqgj.xjd.user.client.*;
import com.fqgj.xjd.user.client.enums.UsagesEnum;
import com.fqgj.xjd.user.client.enums.UserCareerEnum;
import com.fqgj.xjd.user.client.enums.UserGenderEnum;
import com.fqgj.xjd.user.client.response.*;
import com.google.common.base.Strings;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.qianli.cashmama.pay.client.domain.query.response.FundAccountInfoResponse;
import com.qianli.cashmama.pay.client.service.FundPreService;
import com.qianli.cashmama.product.facade.ProductFacade;
import com.qianli.cashmama.product.facade.result.Product;
import com.qianli.cashmama.trade.client.offer.QuoteQueryService;
import com.qianli.cashmama.trade.client.offer.response.OfferResponse;
import com.qianli.cashmama.trade.common.utils.TradeConfigUtil;
import com.qianli.cashmama.trade.common.utils.signature.Base64ConvertUtil;
import com.qianli.cashmama.trade.common.utils.signature.ImageUtil;
import com.qianli.cashmama.trade.domain.model.TradeBase;
import com.qianli.cashmama.trade.integration.pay.PayIntegrationService;
import com.qianli.cashmama.trade.repo.TradeBaseRepository;
import com.qianli.common.enums.BusinessTypeENUM;
import com.qianli.user.facade.query.base.UserBaseInfoQueryServiceFacade;
import com.qianli.user.ro.account.UserAccessRO;
import com.qianli.user.ro.base.UserBaseInfoRO;
import com.qianli.user.ro.base.UserBaseRO;
import com.qianli.user.ro.base.UserResidentRO;
import com.qianli.user.ro.base.UserWorkRO;
import com.qianli.user.ro.query.UserBaseQueryRO;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URL;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author zsp
 */
@Service
public class ContractService {
    private static final Logger LOGGER = LoggerFactory.getLogger(ContractService.class);

    @Autowired
    private TradeConfigUtil tradeConfigUtil;
    //    @MotanReferer(basicReferer = "basicRefererConfig", group = "motan_cashmama_product")
    @Autowired
    private ProductFacade productFacade;
    //@MotanReferer(basicReferer = "basicRefererConfig", group = "motan_cashmama_user")
    @Autowired
    private UserBaseInfoQueryServiceFacade userBaseInfoQueryServiceFacade;
    //@MotanReferer(basicReferer = "basicRefererConfig", group = "motan_cashmama_user")
    @Autowired
    private UserKycDocumentService userKycDocumentService;
    //@MotanReferer(basicReferer = "basicRefererConfig", group = "motan_cashmama_user")
    @Autowired
    private UserPanService userPanService;
    //@MotanReferer(basicReferer = "basicRefererConfig", group = "motan_cashmama_user")
    @Autowired
    private UserBankService userBankService;
    //@MotanReferer(basicReferer = "basicRefererConfig", group = "motan_cashmama_user")
    @Autowired
    private UserContactService userContactService;
    //@MotanReferer(basicReferer = "basicRefererConfig", group = "motan_cashmama_user")
    @Autowired
    private UserEmailService userEmailService;
    @Autowired
    private TradeBaseRepository tradeBaseRepository;
    @Autowired
    private QuoteQueryService quoteQueryService;
    @Autowired
    private PayIntegrationService payIntegrationService;
    @Autowired
    private OSSService ossService;
    @Autowired
    private AmazonS3Service amazonS3Service;
    @Autowired
    private FundPreService fundPreService;

    /**
     * 生成合同
     *
     * @return 接口合同oss地址
     */
    public String createContract(String tradeNo) {
        TradeBase tradeBase = tradeBaseRepository.load(tradeNo);
        return createContract(tradeBase);
    }

    /**
     * 生成合同
     *
     * @return 接口合同oss地址
     */
    public String createContract(TradeBase tradeBase) {
        String contractUrl = "";
        try {
            if (tradeBase.getCapitalCode() == null) {
                return contractUrl;
            }
            FundAccountInfoResponse fundAccountInfoResponse = payIntegrationService.getNbfcByFundCode(tradeBase.getCapitalCode());
            String fileStr = tradeBase.getTradeNo() + "_"
                    + new SimpleDateFormat("yyyy-MM-dd").format(new Date())
                    + "_" + System.currentTimeMillis() + "_Loan_Agreement.pdf";
            InputStream inputStream = Base64ConvertUtil.base64ToPdf(loadPDF(tradeBase, false, fundAccountInfoResponse));
            String ossFilePath = "contractNew/" + DateUtil.getDate(new Date(), "yyyyMMdd") + "/" + fileStr;
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            FileCopyUtils.copy(inputStream, output);
            InputStream swapStream = new ByteArrayInputStream(output.toByteArray());
            amazonS3Service.uploadFile(tradeConfigUtil.getAmazonBucketName(), swapStream, swapStream.available(), ossFilePath);
            contractUrl = tradeConfigUtil.getAmazonS3BaseUrl() + ossFilePath;
            LOGGER.info("生成借款合同: tradeNo:{},contractUrl:{}" + contractUrl);

        } catch (Exception e) {
            LOGGER.error("生成借款合同失败,tradeNo:{}", tradeBase.getTradeNo(), e);
        }
        return contractUrl;
    }

    /**
     * 装载PDF
     */
    String loadPDF(TradeBase tradeBase, boolean withSign, FundAccountInfoResponse fundAccountInfoResponse) {
        try {
            byte[] templateFileBytes = IOUtils.toByteArray(new URL(tradeConfigUtil.getContractPdfUrl()));
            PdfReader reader = new PdfReader(templateFileBytes);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            PdfStamper ps = new PdfStamper(reader, bos);
            AcroFields fields = ps.getAcroFields();
            fillDataToPDF(fields, tradeBase.getTradeNo(), tradeBase.getProductCode(), tradeBase.getUserCode(), ps, withSign, fundAccountInfoResponse);
            ps.setFormFlattening(true);
            ps.close();
            byte[] contractFileBytes = bos.toByteArray();
            return Base64ConvertUtil.pdfToBase64(contractFileBytes);
        } catch (Exception e) {
            LOGGER.error("*** pdf translate exception, tradeNo:" + tradeBase.getTradeNo() + " ***", e);
            throw new ApplicationException("pdf translate exception");
        }
    }

    /**
     * 替换pdf上的字段
     *
     * @param fields
     * @param tradeNo
     * @param productCode
     * @param userCode
     * @param ps
     * @param withSign
     * @param fundAccountInfoResponse
     * @throws IOException
     * @throws DocumentException
     */
    private void fillDataToPDF(AcroFields fields, String tradeNo, String productCode, String userCode,
                               PdfStamper ps, boolean withSign, FundAccountInfoResponse fundAccountInfoResponse) throws IOException, DocumentException {
        try {
            // 产品费用相关数据准备
            Product productInfo = productFacade.getProductDetail(productCode, false).getData();
            if (productInfo == null) {
                LOGGER.info("*** get product info exception, productCode:{} ***", productCode);
                throw new ApplicationException("get product info exception");
            }
            Response<OfferResponse> rsp = Optional.ofNullable(quoteQueryService.quoteDetail(productCode))
                    .filter(Response::isSuccess)
                    .orElseThrow(() -> new ApplicationException("Query Product Info Failed"));
            BigDecimal ratePerMonth = new BigDecimal(productInfo.getRate())
                    .multiply(BigDecimal.valueOf(100))
                    .divide(new BigDecimal("12"), 2, BigDecimal.ROUND_HALF_UP);

            NumberFormat format = NumberFormat.getPercentInstance();
            format.setMaximumFractionDigits(3);
            // 月利率 带百分号
            String ratePerMonthStr = ratePerMonth + "%";
            // 年利率 带百分号
            String ratePerYearStr = new BigDecimal(productInfo.getRate()).multiply(new BigDecimal(100)).intValue() + "%";
            String interest = rsp.getData().getOfferList().get(0).getInterestFee();
            // 利息
            BigDecimal emiAmount = DecimalUtils.add(new BigDecimal(productInfo.getPrincipalMoney()), new BigDecimal(interest));
            // 本金 + 利息
            String emiAmountStr = DecimalUtils.roundToString(emiAmount);


            // 准备数据
            String dataMock = new SimpleDateFormat("dd-MM-yyyy").format(new Date());
            UserBaseQueryRO userBaseQueryRO = new UserBaseQueryRO();
            userBaseQueryRO.setUserCode(userCode);
            userBaseQueryRO.setBiz(BusinessTypeENUM.XJD.getCode());
            userBaseQueryRO.setAppCode("");
            Response<UserBaseInfoRO> userBaseInfoResponse = userBaseInfoQueryServiceFacade.getUserBaseInfo(userBaseQueryRO);
            Response<List<UserKycDocumentInfo>> kycInfoResponse = userKycDocumentService.getByUserCode(userCode);

            if (!kycInfoResponse.isSuccess()) {
                LOGGER.info("*** get user kyc info exception, userCode:{} ***", userCode);
                throw new ApplicationException(kycInfoResponse.getMsg());
            }

            if (!userBaseInfoResponse.isSuccess()) {
                LOGGER.info("*** get user base info exception, userCode:{} ***", userCode);
                throw new ApplicationException(userBaseInfoResponse.getMsg());
            }
            Response<UserPanInfo> userPanInfoResponse = userPanService.getByUserCode(userCode);
            if (!userPanInfoResponse.isSuccess()) {
                LOGGER.info("*** get user pan info exception, userCode:{} ***", userCode);
                throw new ApplicationException(userPanInfoResponse.getMsg());
            }
            Response<UserBankInfo> userBankInfoResponse = userBankService.getByUserCode(userCode);
            if (!userBankInfoResponse.isSuccess()) {
                LOGGER.info("*** get user bank info exception, userCode:{} ***", userCode);
                throw new ApplicationException(userBankInfoResponse.getMsg());
            }
            Response<UserSocialContact> userSocialContactResponse = userContactService.getUserSocialContactByUserCode(userCode);
            if (!userSocialContactResponse.isSuccess()) {
                LOGGER.info("*** get user social contact info exception, userCode:{} ***", userCode);
                throw new ApplicationException(userSocialContactResponse.getMsg());
            }
            Response<UserAuthEmail> userEmailResponse = userEmailService.getUserEmail(userCode);
            if (!userEmailResponse.isSuccess()) {
                LOGGER.info("*** get user email exception, userCode:{} ***", userCode);
                throw new ApplicationException(userEmailResponse.getMsg());
            }
            //TODO 以后要强校验
            UserAuthEmail userAuthEmail = userEmailResponse.getData();
            if (userAuthEmail == null) {
                userAuthEmail = new UserAuthEmail();
            }
            UserBaseInfoRO userBaseInfo = userBaseInfoResponse.getData();
            if (userBaseInfo == null) {
                userBaseInfo = new UserBaseInfoRO();
            }

            UserBaseRO userBaseRO = userBaseInfo.getUserBase();
            if (userBaseRO == null) {
                userBaseRO = new UserBaseRO();
            }
            UserResidentRO userResidentRO = userBaseInfo.getUserResident();
            if (userResidentRO == null) {
                userResidentRO = new UserResidentRO();
            }
            UserWorkRO userWorkRO = userBaseInfo.getUserWork();
            if (userWorkRO == null) {
                userWorkRO = new UserWorkRO();
            }
            UserPanInfo userPanInfo = userPanInfoResponse.getData();
            if (userPanInfo == null) {
                userPanInfo = new UserPanInfo();
            }
            UserBankInfo userBankInfo = userBankInfoResponse.getData();
            if (userBankInfo == null) {
                userBankInfo = new UserBankInfo();
            }
            UserSocialContact userSocialContact = userSocialContactResponse.getData();
            UserFriendContact userFriendContact = new UserFriendContact();
            if (userSocialContact != null && userSocialContact.getUserEmergencyContact() != null && userSocialContact.getUserEmergencyContact().getUserFriendContact() != null) {
                userFriendContact = userSocialContact.getUserEmergencyContact().getUserFriendContact();
            }
            UserAccessRO userAccessRO = userBaseInfo.getUser();
            if (userAccessRO == null) {
                userAccessRO = new UserAccessRO();
            }

            List<UserKycDocumentInfo> kycInfoList = kycInfoResponse.getData();
            UserKycDocumentInfo userKycDocumentInfo = new UserKycDocumentInfo();
            userKycDocumentInfo = kycInfoList.get(0);


            // 图片地址
            String imagePath1 = userKycDocumentInfo.getCardFrontUrl();
            String imagePath2 = userKycDocumentInfo.getCardBackUrl();
            String imagePath3 = userPanInfo.getCardUrl();
            String imagePath4 = userKycDocumentInfo.getHandHoldUrl();
            String aadhaarImg1 = "aadhaar_front_img_af_image";
            String aadhaarImg2 = "aadhaar_back_img_af_image";
            String panCardImg = "pan_card_img_af_image";
            String lifeImg = "life_img_af_image";
            fillImgToPDF(imagePath1, aadhaarImg1, fields, ps);
            fillImgToPDF(imagePath2, aadhaarImg2, fields, ps);
            fillImgToPDF(imagePath3, panCardImg, fields, ps);
            fillImgToPDF(imagePath4, lifeImg, fields, ps);

            // 填装字段
            String userName = userBaseRO.getFirstName() + " " + userBaseRO.getLastName();

            Map<String, String> data = new HashMap<>();
            data.put("account_type", "Personal");
            data.put("name", userName);
            data.put("father_or_spouse_name", userBaseRO.getFatherName());
            data.put("mother_name", userBaseRO.getMotherName());
            data.put("date_of_birth", userBaseRO.getBirthday());
            data.put("gender", UserGenderEnum.getEnumByCode(userBaseRO.getGender()).toString());  // Male Female ===
            data.put("marital_status", userBaseRO.getMarriedStatus() == 0 ? "Single" : "Married");

            UserCareerEnum userCareerEnum = UserCareerEnum.getEnumByType(userWorkRO.getCareerType());
            userCareerEnum = userCareerEnum == null ? UserCareerEnum.Other : userCareerEnum;
            data.put("occupation", userCareerEnum.getDesc());
            data.put("nationality", "INDIAN");
            data.put("residential_status", "INDIAN");
            data.put("proof_of_identity", "PAN");
            data.put("pan", userPanInfo.getCardNo());
            data.put("proof_of_address", userKycDocumentInfo.getAuthType().getDesc());
            data.put("address_type", "PERMANENT");
            data.put("address", userResidentRO.getPermanentAddress());
            data.put("address_2", userResidentRO.getPermanentState() + "," + userResidentRO.getPermanentCity());
            data.put("address_3", "");
            data.put("address_4", "");
            data.put("current_address", userResidentRO.getAddress());
            data.put("current_address_2", userResidentRO.getProvince() + "," + userResidentRO.getCity());
            data.put("current_address_3", "");
            data.put("current_address_4", "");
            data.put("phone_number", Strings.nullToEmpty(userAccessRO.getMobile()));
            data.put("email", userAuthEmail.getEmail());
            data.put("name_of_bank", userBankInfo.getName());
            data.put("bank_ac_no", userBankInfo.getCardNo());
            data.put("ifsc", userBankInfo.getCode());
            data.put("name_of_related_person", userFriendContact.getName());
            data.put("phone_number_of_related_person", userFriendContact.getMobile());
            data.put("loan_id_or_serial_id", tradeNo);
            data.put("city", userResidentRO.getCity());
            data.put("lender", fundAccountInfoResponse.getNbfcCompanyName());
            data.put("nbfc_loc", fundAccountInfoResponse.getNbfcLocation());
            data.put("nbfc_address", fundAccountInfoResponse.getNbfcLocation());
            data.put("platform", "www.cashmama.in");
            //TODO  待讨论解决方案
            if (productInfo.getCode().toLowerCase().contains("dhanadhan")) {
                data.put("platform", "dhanadhanloans.in");
            } else if (productInfo.getCode().toLowerCase().contains("loanzone")) {
                data.put("platform", "www.loanzon.in");
            } else if (productInfo.getCode().toLowerCase().contains("cashzone")) {
                data.put("platform", "blueshieldfintech.com");
            } else if (productInfo.getCode().toLowerCase().contains("meraloan")) {
                data.put("platform", "credonomics.com");
            }
            if ("Faircent".equalsIgnoreCase(fundAccountInfoResponse.getNbfc())) {
                data.put("interest_comment", "(Inclusive of 19% payable to the platform for Fund Management Fees)");
                data.put("faircent", "16.Borrower authorizes Faircent.com to enter into subsequent one-to-one loan agreements on his/her behalf, with various lenders, for arranging funds to fulfil this loan. ");
            }
            data.put("loan_amount", productInfo.getPrincipalMoney());
            data.put("rete_of_interest", ratePerYearStr);
            UsagesEnum usagesEnum = UsagesEnum.getEnumByType(userBaseRO.getUsages());
            usagesEnum = usagesEnum == null ? UsagesEnum.CONSUME : usagesEnum;
            data.put("purpose_of_loan", usagesEnum.getDesc());
            data.put("fees_and_charges", "0");
            data.put("procession_fees", productInfo.getServiceCharge());
            data.put("service_charges", "0");
            data.put("full_prepayment_charges", "N/A");
            data.put("part_prepayment_charges", "N/A");
            data.put("default_charges", productInfo.getOverdueServiceCharge());
            data.put("cheque_bounce", "N/A");
            data.put("cheque_swap", "N/A");
            data.put("document_retrieval", "N/A");
            data.put("nach_dishonor", "0");
            data.put("documents_from_the_applicant_no_1", "PAN");
            data.put("documents_from_the_applicant_no_2", userKycDocumentInfo.getAuthType().getDesc());
            data.put("documents_from_the_applicant_no_3", "");
            data.put("documents_from_the_applicant_no_4", "");
            data.put("drawdown_request_date", dataMock);
            data.put("drawdown_request_money", productInfo.getProtocol());
            data.put("name_of_the_beneficiary", userName);
            data.put("name_of_the_bank", userBankInfo.getName());
            data.put("account_holder_name", userName);
            data.put("account_number", userBankInfo.getCardNo());
            data.put("type_of_account", "N/A");                                                 //银行卡类型 ?
            data.put("ifsc_code", userBankInfo.getCode());
            data.put("micr_code", "N/A");                                                             // ??
            data.put("doandown_request_5_1", productInfo.getServiceCharge());
            data.put("doandown_request_5_2", "N/A");
            data.put("doandown_request_5_3", "N/A");
            data.put("doandown_request_5_4", "N/A");
            data.put("annexure_a_date", dataMock);
            data.put("borrower", userName);
            data.put("facility_type", "Personal Loan");
            data.put("max_amount_sanctioned", productInfo.getPrincipalMoney());
            data.put("purpose", usagesEnum.getDesc());
            data.put("tenure", productInfo.getPaybackPeriodLength().toString());
            data.put("rate_of_interest_pa", ratePerYearStr);
            data.put("rate_of_interest_pm", ratePerMonthStr);
            data.put("emi_amount", emiAmountStr);
            data.put("risk_category", "Low");
            data.put("annexure_loan_amount", productInfo.getPrincipalMoney());

            for (String key : data.keySet()) {
                String value = data.get(key);
                fields.setField(key, value);
            }
            //LOGGER.info("fileParams is {}", JSONObject.toJSONString(data));
        } catch (Exception e) {
            LOGGER.error("file data to PDF exception", e);
            throw e;
        }
    }


    /**
     * 拼装图片
     *
     * @param imagePath 图片路径
     * @param tag       表签名
     */
    private static void fillImgToPDF(String imagePath, String tag, AcroFields fields, PdfStamper ps) throws IOException, DocumentException {

        try {
            // 装载图片
            // 通过域名获取所在页和坐标，左下角为起点
            LOGGER.info("fillImgToPDF params {}, {}", imagePath, tag);
            int pageNo = fields.getFieldPositions(tag).get(0).page;
            Rectangle signRect = fields.getFieldPositions(tag).get(0).position;
            float x = signRect.getLeft();
            float y = signRect.getTop();

            // 读图片
            //Image image = Image.getInstance(imagePath);
            byte[] bytes = ImageUtil.compressPic(imagePath, 0.25f);
            Image image = Image.getInstance(bytes);

            // 获取操作的页面
            PdfContentByte under = ps.getOverContent(pageNo);
            // 根据域的大小缩放图片
            image.scaleToFit(signRect.getWidth(), 260);
            // 添加图片
            image.setAbsolutePosition(x, y);
            under.addImage(image);
            under.stroke();
        } catch (Exception e) {
            LOGGER.error("fillImgToPDF error", e);
        }

    }


}
